package cn.safekeeper.plugin.configuration;

import cn.safekeeper.common.configuration.SafeKeeperCodeMsgConfiguration;
import cn.safekeeper.common.configuration.SafeKeeperConfiguration;
import cn.safekeeper.common.model.SafeKeeperAuthorizationCallBack;
import cn.safekeeper.common.model.SafeKeeperContext;
import cn.safekeeper.common.utils.SafeKeeperUtils;
import cn.safekeeper.core.SafeKeeper;
import cn.safekeeper.core.listener.SafeKeeperTokenListener;
import cn.safekeeper.core.manager.SafeKeeperManager;
import cn.safekeeper.core.manager.SafeKeeperTokenRealm;
import cn.safekeeper.plugin.aop.SafeKeeperCheckAspect;
import cn.safekeeper.plugin.context.SpringSafeKeeperContext;
import cn.safekeeper.plugin.filter.SafeKeeperFilter;
import cn.safekeeper.plugin.redis.config.SafeRedisProperties;
import cn.safekeeper.plugin.redisson.dao.SafeKeeperTokenRealmRedisson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.servlet.http.HttpServletRequest;

/**
 * SafeKeeper配置启动类
 * @author skylark
 */
@Configuration
@ComponentScan("cn.safekeeper.plugin.web")
public class SafeKeeperAutoConfiguration {

    /**
     * 切面初始化
     */
    @Bean
    public SafeKeeperCheckAspect getSafeKeeperCheckAspect(){
        return new SafeKeeperCheckAspect();
    }

    /**
     * context初始化
     */
    @Bean
    public SafeKeeperContext getSafeKeeperContext(){
        return new SpringSafeKeeperContext();
    }

    @Bean
    @ConfigurationProperties(prefix ="spring.safekeeper")
    public SafeKeeperConfiguration getSafeKeeperConfiguration(){
        return new SafeKeeperConfiguration();
    }


    /**
     * SafeKeeperManager 注入 SafeKeeperConfiguration
     * 配置文件 Bean
     */
    @Autowired
    public void setConfig(SafeKeeperConfiguration config){
        SafeKeeperManager.setConfig(config);
    }

    @Bean
    public SafeRedisProperties getSafeRedisProperties(){
        return new SafeRedisProperties();
    }

    @Bean
    public SafeKeeperTokenRealm safeKeeperTokenRealmRedisson(SafeRedisProperties cfg){
        return new SafeKeeperTokenRealmRedisson(cfg);
    }

    /**
     * SafeKeeperManager SafeKeeperTokenDaoStorage
     * 持久化Dao Bean
     */
    @Autowired
    public void setSafeKeeperTokenRealm(SafeKeeperTokenRealm safeKeeperTokenRealm) {
        SafeKeeperManager.setSafeKeeperTokenRealm(safeKeeperTokenRealm);
    }

    /**
     *
     * SafeKeeperManager SafeKeeperAuthorizationCallBack
     * 权限认证 Bean
     */
    @Autowired(required = false)
    public void setStpInterface(SafeKeeperAuthorizationCallBack authorizationCallBack) {
        SafeKeeperManager.setSafeKeeperAuthorizationCallBack(authorizationCallBack);
    }

    /**
     * 容器操作 Bean
     */
    @Autowired
    public void setSafeKeeperContext(SafeKeeperContext safeKeeperContext) {
        SafeKeeperManager.setSafeKeeperContext(safeKeeperContext);
    }

    /**
     * SafeKeeperManager SafeKeeperTokenListener
     * 侦听器 Bean
     */
    @Autowired(required = false)
    public void setSafeKeeperTokenListener(SafeKeeperTokenListener tokenListener) {
        SafeKeeperManager.setSafeKeeperTokenListener(tokenListener);
    }

    /**
     * SafeKeeperManager SafeKeeperCodeMsgConfiguration
     * 状态消息配置 Bean
     */
    @Autowired(required = false)
    public void setSafeKeeperCodeMsgConfiguration(SafeKeeperCodeMsgConfiguration safeKeeperCodeMsgConfiguration) {
        SafeKeeperManager.setSafeKeeperCodeMsgConfiguration(safeKeeperCodeMsgConfiguration);
    }

    @Bean
    public SafeKeeperFilter getSaServletFilter(SafeKeeperConfiguration config) {
        return new SafeKeeperFilter()
                // 指定 拦截路由 与 放行路由
                .addInclude("/**")
                .addExclude("/favicon.ico")
                .addExclude("/login")
                .addExclude("/safe/*")
                .addExclude("/static/*")
                .addExclude("/error")
                .setExcludeList(config.getExcludeList())
                .setIncludeList(config.getIncludeList())
                // 认证函数: 每次请求执行
                .setAuth(r -> {
                    HttpServletRequest request=(HttpServletRequest)r;
                    //获取登录的方式
                    String loginType = request.getHeader("loginType");
                    //如果header中的数据为空，尝试去参数中获取。
                    if(SafeKeeperUtils.isEmpty(loginType)){
                        //对参数进行获取loginType
                        loginType=request.getParameter("loginType");
                    }
                    //如果用户是没有带loginType的参数，那么就默认是safekeeper维度进行登录
                    if(SafeKeeperUtils.isEmpty(loginType)){
                        loginType=SafeKeeperManager.getConfig().getDefaultLoginType();
                    }
                    SafeKeeper.safeLogic(loginType).checkLogin();
                })
                // 异常处理函数：每次认证函数发生异常时执行此函数
                .setError(Throwable::getMessage)
                // 前置函数：在每次认证函数之前执行
                .setBeforeAuth(r -> {
                    //安全响应头
                    SafeKeeperManager.getSafeKeeperContext().getResponse()
                            .setServer("safekeeper-server")
                            .setHeader("X-XSS-Protection", "1; mode=block")
                            .setHeader("X-Content-Type-Options", "nosniff");
                });
    }
}
